#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>

#define BLOCK_SIZE 1024                             //块大小(字节)
#define USER_NUM ((BLOCK_SIZE / 64) - 1)            //系统支持的最大用户数(含超级用户)
#define I_BLOCK_NUM 64                              //i节点块数目
#define I_NUM (I_BLOCK_NUM * BLOCK_SIZE / 64)       //i节点个数
#define DATA_NUM 1024                               //目录和数据块数目
#define FILE_SYS_SIZE (2 + I_BLOCK_NUM + DATA_NUM)  //整个文件系统块数：1090Kb=1(引导块)+1(超级块)+64(i节点)+1024(目录和数据区)
#define I_START (2 * BLOCK_SIZE)                    //i节点块起始字节地址
#define DATA_START ((2 + I_BLOCK_NUM) * BLOCK_SIZE) //目录和数据块起始字节地址
#define B_FREE_NUM 100                              //空闲块号栈大小
#define I_FREE_NUM 32                               //空闲i节点号栈大小
#define I_ADDR_NUM 10                               //i节点数据指针数目
#define DIR_NUM (BLOCK_SIZE / 32)                   //每个块可以存放的目录项个数

#define I(x) (I_START + ((x)-1) * 64)            //获取第x个i节点的起始地址
#define D(x) (DATA_START + ((x)-1) * BLOCK_SIZE) //获取第x个数据块的起始地址

enum file_type //文件类型
{
    NORMAL,
    DIR,
    PWD,
    SUPBLK,
    LINK,
    PIPE
};

enum file_perm //文件权限
{
    READ = 1,
    WRITE,
    RUN = 4
};

typedef struct _lead_block //引导块
{
    int flag; //文件是否经过格式化标志
} lead_block;

typedef struct _super_block //超级块，占用一个块
{
    unsigned s_isize;             // i节点区总块数
    unsigned s_fsize;             // 文件卷总块数
    unsigned s_nfree;             // 直接管理的空闲块数
    unsigned s_free[B_FREE_NUM];  // 空闲块号栈
    unsigned s_ninode;            // 直接管理的空闲i节点数
    unsigned s_inode[I_FREE_NUM]; // 空闲i节点号栈
    long s_time;                  // 文件卷最近修改时间
} super_block;

typedef struct _direct //目录项，每个占用32个字节
{
    unsigned dir_id;   //目录号,即i节点号
    char dir_name[28]; //文件或文件目录名
} dir_entry;

typedef struct _inode //i节点，每个i节点占用64个字节
{
    unsigned short i_uid;        //文件所有者标识 0:root
    unsigned short i_type;       //文件类型标识
    unsigned short i_mode;       //文件存取许可
    unsigned short i_ilink;      //联接计数
    unsigned i_addr[I_ADDR_NUM]; //地址索引表 0-8:直接 9:一级间接
    unsigned i_size;             //文件长度
    time_t i_time;               //文件存取时间
} inode;

typedef struct _directory //目录文件块
{
    dir_entry entry[DIR_NUM];
} dirs;

struct pwd_entry //用户信息条目, 一个用户, 64字节
{
    unsigned short p_uid;
    char user_name[28]; //用户名
    char password[32];  //密码
};

typedef struct _pwd //用户信息
{
    struct pwd_entry entry[USER_NUM];
    unsigned short current_usr, all_usr; //当前用户、全部用户数目
} pwd;

FILE *fp = NULL;
super_block su_b;           //超级块缓冲区
pwd pd;                     //用户账户密码缓冲区
inode ino, t_ino, open_ino; //i节点缓冲区
dirs dir;                   //文件目录缓冲区
unsigned current_i;         //当前i节点号
unsigned open_i;            //当前打开的i节点号

unsigned ialloc();                                   //申请一个未使用的i节点号
bool ifree(unsigned num);                            //归还一个i节点号
bool iread(inode *i, unsigned num);                  //读取第num个i节点到内存
bool iwrite(inode *i, unsigned num);                 //写第num个i节点到磁盘
bool set_imode(inode *i, const char *mode);          //设置各类用户权限
unsigned balloc();                                   //申请一个空数据块
bool bfree(unsigned num);                            //归还一个数据块
bool bread(void *buf, unsigned num, unsigned mode);  //读取第num个数据块到内存，mode:文件类型
bool bwrite(void *buf, unsigned num, unsigned mode); //写入数据到第num个数据块，mode:文件类型

bool format();                                                                //格式化文件系统
bool loadSystem();                                                            //载入文件系统
bool printCommandTip();                                                       //打印命令提示头
bool checkRWX(unsigned cur_i, unsigned rwx);                                  //权限检测
bool addFileToDir(char *file_name, unsigned src_i, unsigned des_i);           //向目标i节点目录加入文件
bool checkName(char *file_name, unsigned cur_i);                              //判断当前目录下是否有同名文件
bool refrushTime(char *file_name, unsigned cur_i);                            //更新文件或目录时间戳
bool createFile(char *file_name, unsigned mode);                              //创建新文件，mode:文件类型
bool appendChar(char *des, char *src, int d_begin, int s_begin, int len);     //在char数组特定位置追加数据
bool catFile(char *file_path);                                                //查看文件内容
bool vi_file(char *file_path);                                                //编辑文件
void getAuthorityBuf(char *buf, unsigned short mode);                         //将文件权限转换为字符串
bool showDir(char *mode);                                                     //显示当前文件夹中内容
int filePath2inode(char *path, unsigned cur_i, unsigned mode, unsigned type); //根据文件路径找到该文件i节点号
bool changeDir(char *path, unsigned cur_i);                                   //改变当前工作目录
bool inode2name(unsigned far_i, unsigned cur_i, char *name);                  //根据父文件和文件i节点获取文件名
bool printWorkingDir(char *workpath, unsigned cur_i);                         //获取当前工作目录路径
bool relative2absolute(char *path, unsigned cur_i);                           //相对路径转绝对路径
unsigned getFartherInode(char *filepath);                                     //获取filepath的父亲i节点, filepath为绝对路径
bool removeNormalFile(unsigned rm_i);                                         //删除普通文件
bool removeFileFromFar(unsigned far_i, unsigned rm_i);                        //从far_i目录中删除rm_i节点
bool removeDirFile(unsigned rm_i);                                            //删除文件
bool removeFile(char *filepath, unsigned type);                               //删除文件, type: 文件种类
void printHelp();                                                             //打印显示帮助信息

bool _open(char *file_name);       //打开文件
int _read(int loc, char *buf);     //读取已经打开了的文件，每次读取一个数据块
int _write(char *buf, int length); //写入已经打开的文件
bool _close(unsigned close_i);     //关闭已经打开的文件

bool changeUsr();           //更改登录用户
bool addUsr();              //增加用户，仅root用户
bool removeUsr(char *name); //删除用户，仅root用户
bool lsUsr();               //显示所有用户信息，仅root用户

bool workLoop();   //工作循环
bool exitSystem(); //退出系统